package com.dev.widget.ui;


import com.dev.utils.LogUtils;
import com.dev.utils.app.ResourceUtils;
import dev.widget.ResourceTable;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.Point;
import ohos.app.Context;
import ohos.global.configuration.Configuration;

import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;

public class FlowLikeView extends StackLayout {

    private static final String TAG = FlowLikeView.class.getSimpleName();

    // 在 XML 布局文件中添加的子 View 的总高度
    private int mChildViewHeight;
    // View 宽度、高度
    private int mViewWidth, mViewHeight;
    // 添加动画 View Layout 参数
    private LayoutConfig mLayoutParams;
    // 用于产生随机数
    private Random mRandom;
    // Icon 集合
    private List<Element> mDrawables;
    // 点赞 Icon 宽高
    private int mIconWidth, mIconHeight;
    // 点赞动画执行时间
    private long mAnimDuration = 2000L;

    private AttrSet attrs;
    private List<AnimatorGroup> animatorGroupList;
    private int index = 1;

    public void cleanAnimator() {
        release();
    }


    public FlowLikeView(Context context) {
        super(context);
        attrs = null;
        initAttrs(context);
    }

    public FlowLikeView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        attrs = attrSet;
        initAttrs(context);
    }

    public FlowLikeView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        attrs = attrSet;
        initAttrs(context);
    }


    /**
     * 初始化
     *
     * @param context {@link Context}
     */
    private void initAttrs(Context context) {
        // 初始化操作
        mRandom = new Random();
        mDrawables = new ArrayList<>();

        if (context != null && attrs != null) {
            try {
                mAnimDuration = getInteger(attrs.getAttr(getResourceManager().getElement(ResourceTable.String_dev_animDuration).getString()), 200);

                mIconWidth = getLayoutDimension(attrs.getAttr(getResourceManager().getElement(ResourceTable.String_dev_iconWidth).getString()), 0);
                mIconHeight = getLayoutDimension(attrs.getAttr(getResourceManager().getElement(ResourceTable.String_dev_iconHeight).getString()), 0);
            } catch (NotExistException e) {
                e.printStackTrace();
            } catch (WrongTypeException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        LogUtils.error("FlowLikeView", "mIconWidth = " + mIconWidth + " mIconHeight = " + mIconHeight);
        // 重置 LayoutParams
        resetLayoutParams();

        animatorGroupList = new ArrayList<>();
        mViewWidth = getWidth();
        mViewHeight = getHeight();

        setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                if (mChildViewHeight <= 0) {
                    LogUtils.error(TAG, "count = " + getChildCount());
                    for (int i = 0, size = getChildCount(); i < size; i++) {
                        Component childView = getComponentAt(i);
                        mChildViewHeight += childView.getEstimatedHeight();
                    }
                    // 重置 LayoutParams
                    resetLayoutParams();
//            // 设置底部间距 ( 防止当 addView 显示与动画起始位置相差太远 )
//            mLayoutParams.bottomMargin = mChildViewHeight;
                }
            }
        });
    }

    /**
     * 重置 LayoutParams
     */
    private void resetLayoutParams() {
        mLayoutParams = new LayoutConfig(mIconWidth, mIconHeight);
        mLayoutParams.alignment = LayoutAlignment.HORIZONTAL_CENTER | LayoutAlignment.BOTTOM;

        LogUtils.error(TAG, "mChildViewHeight = " + mChildViewHeight);

        // 设置底部间距 ( 防止当 addView 显示与动画起始位置相差太远 )
        mLayoutParams.setMarginBottom(mChildViewHeight);
    }

    /**
     * 获取 Icon 集合
     *
     * @return Icon 集合
     */
    public List<Element> getDrawables() {
        return mDrawables;
    }

    /**
     * 设置 Icon 集合
     *
     * @param drawables Icon 集合
     * @return {@link FlowLikeView}
     */
    public FlowLikeView setDrawables(List<Element> drawables) {
        this.mDrawables.clear();
        if (drawables != null) {
            this.mDrawables.addAll(drawables);
            // 如果没有设置 Icon 宽高则获取传入的 Icon 集合宽高
            if (mIconWidth == 0 || mIconHeight == 0) {
                for (Element drawable : drawables) {
                    if (drawable != null) {
                        mIconWidth = drawable.getWidth();
                        mIconHeight = drawable.getHeight();
                        resetLayoutParams();
                        break;
                    }
                }
            }
        }
        return this;
    }

    /**
     * 设置 Icon 集合
     *
     * @param drawableIds Icon 集合
     * @return {@link FlowLikeView}
     */
    public FlowLikeView setDrawablesById(final int... drawableIds) {
        if (drawableIds != null) {
            List<Element> lists = new ArrayList<>();
            for (int drawableId : drawableIds) {
                Element drawable = ResourceUtils.getDrawable(drawableId);
                lists.add(drawable);
            }
            return setDrawables(lists);
        }
        return this;
    }

    /**
     * 获取点赞 Icon 宽度
     *
     * @return 点赞 Icon 宽度
     */
    public int getIconWidth() {
        return mIconWidth;
    }

    /**
     * 设置点赞 Icon 宽度
     *
     * @param iconWidth 点赞 Icon 宽度
     * @return {@link FlowLikeView}
     */
    public FlowLikeView setIconWidth(int iconWidth) {
        this.mIconWidth = iconWidth;
        resetLayoutParams();
        return this;
    }

    /**
     * 获取点赞 Icon 高度
     *
     * @return 点赞 Icon 高度
     */
    public int getIconHeight() {
        return mIconHeight;
    }

    /**
     * 设置点赞 Icon 高度
     *
     * @param iconHeight 点赞 Icon 高度
     * @return {@link FlowLikeView}
     */
    public FlowLikeView setIconHeight(int iconHeight) {
        this.mIconHeight = iconHeight;
        resetLayoutParams();
        return this;
    }

    /**
     * 获取点赞动画执行时间
     *
     * @return 点赞动画执行时间
     */
    public long getAnimDuration() {
        return mAnimDuration;
    }

    /**
     * 设置点赞动画执行时间
     *
     * @param animDuration 点赞动画执行时间
     * @return {@link FlowLikeView}
     */
    public FlowLikeView setAnimDuration(long animDuration) {
        this.mAnimDuration = animDuration;
        return this;
    }

    @Override
    protected void onAttributeConfigChanged(Configuration config) {
        super.onAttributeConfigChanged(config);
        mViewWidth = getWidth();
        mViewHeight = getHeight();
    }


    // ===============
    // = 对外公开方法 =
    // ===============

    /**
     * 点赞操作
     */
    public void like() {
        //LogUtils.error(TAG, "like ");
        int iconSizes = mDrawables.size();
        if (iconSizes != 0) {
            Image likeView = null;
            if (getChildCount() < 15) {
                likeView = new Image(getContext());
                likeView.setImageElement(mDrawables.get(mRandom.nextInt(iconSizes)));
                likeView.setLayoutConfig(mLayoutParams);
                addComponent(likeView);
            } else {
                likeView = (Image) getComponentAt(index);
                if (index >= 14) {
                    index = 1;
                } else {
                    index++;
                }
            }
            startAnimation(likeView);
        }
        getCountChild();
    }

    /**
     * 开始动画处理
     *
     * @param target 动画作用 View
     */
    private void startAnimation(Component target) {
        // LogUtils.error(TAG, "width = " + mViewWidth + " height = " + mViewHeight);
        // 进入动画
        AnimatorValue enterAnimator = generateEnterAnimation(target);
        // 路径动画
        AnimatorValue curveAnimator = generateCurveAnimation(target);
        AnimatorGroup finalAnimatorSet = new AnimatorGroup();
        AnimatorGroup.Builder animatorGroupBuilder = finalAnimatorSet.build();
        // 设置动画集合, 先执行进入动画, 最后再执行运动曲线动画
        animatorGroupBuilder.addAnimators(enterAnimator, curveAnimator);
        finalAnimatorSet.start();
    }

    /**
     * 生成进入动画
     *
     * @param target 动画作用 View
     * @return 动画集合
     */
    private AnimatorValue generateEnterAnimation(Component target) {
        AnimatorValue enterAnimation = new AnimatorValue();
        enterAnimation.setDuration(10);
        enterAnimation.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                target.setAlpha(0.2f + 0.8f * v);
                target.setScaleX(0.5f + 0.5f * v);
                target.setScaleY(0.5f + 0.5f * v);
            }
        });
        invalidate();
        return enterAnimation;
    }

    private AnimatorValue generateCurveAnimation(Component target) {
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDuration(mAnimDuration);
        animatorValue.setValueUpdateListener(new CurveUpdateLister(target));

        return animatorValue;
    }


    /**
     * 动画途径计算
     */
    private class CurveUpdateLister implements AnimatorValue.ValueUpdateListener {
        private final Component target;
        private Point startPoint;
        private Point endPoint;
        private Point ctrlPoint;

        public CurveUpdateLister(Component target) {
            this.target = target;
            ctrlPoint = generateCTRLPointF(1);
            startPoint = new Point((mViewWidth - mIconWidth) / 2, mViewHeight - mChildViewHeight - mIconHeight);
            endPoint = new Point((mViewWidth) / 2 + (mRandom.nextBoolean() ? 1 : -1) * mRandom.nextInt(100), 0);
        }

        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {


            float leftTime = 1.0f - v;

            float tempX = (float) Math.pow(leftTime, 2) * startPoint.getPointX() + 2 * v * leftTime * ctrlPoint.getPointX()
                    + ((float) Math.pow(v, 2)) * endPoint.getPointX();
            float tempY = (float) Math.pow(leftTime, 2) * startPoint.getPointY() + 2 * v * leftTime * ctrlPoint.getPointY()
                    + ((float) Math.pow(v, 2)) * endPoint.getPointY();


            if (target != null) {
                target.setContentEnable(true);
                target.setContentPositionX(tempX);
                target.setContentPositionY(tempY);
                //LogUtils.error(TAG, "target = " + target + " tempX = " + tempX + " tempY = " + tempY);
                target.setAlpha(1 - v);
                invalidate();
            }


        }
    }

    /**
     * 生成贝塞儿曲线的控制点
     *
     * @param value 设置控制点 y 轴上取值区域
     * @return 控制点的 x y 坐标
     */
    private Point generateCTRLPointF(int value) {
        Point pointF = new Point();
        pointF.modify(mViewWidth / 2 - mRandom.nextInt(100), mRandom.nextInt(mViewHeight / value));
        return pointF;
    }


    private int getInteger(Optional<Attr> attr, int defaultValue) throws NotExistException, WrongTypeException, IOException {
        if (attr.isPresent()) {
            return attr.get().getIntegerValue();
        } else {
            return defaultValue;
        }
    }

    private int getLayoutDimension(Optional<Attr> attr, int defaultValue) throws NotExistException, WrongTypeException, IOException {
        if (attr.isPresent()) {
            LogUtils.error(TAG, "isPresent = " + true);
            return attr.get().getDimensionValue();
        } else {
            return defaultValue;
        }
    }

    private void getCountChild() {
        int chlidCount = getChildCount();
        LogUtils.error(TAG, "childCount = " + chlidCount);
    }

}


